/* * Copyright (c) 2015-present, Facebook, Inc. * All rights reserved. * * This source code is licensed under the BSD-style license found in the * LICENSE file in the root directory of this source tree. An additional grant * of patent rights can be found in the PATENTS file in the same directory. */ package com.facebook.common.executors; import java.lang.reflect.Field; import java.util.ConcurrentModificationException; import java.util.concurrent.atomic.AtomicInteger; import com.facebook.testing.robolectric.v2.WithTestDefaultsRunner; import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; import org.mockito.InOrder; import static org.junit.Assert.*; import static org.mockito.Mockito.*; @RunWith(WithTestDefaultsRunner.class) public class StatefulRunnableTest { private StatefulRunnable mStatefulRunnable; private Object mResult; private ConcurrentModificationException mException; @Before public void setUp() throws Exception { mResult = new Object(); mException = new ConcurrentModificationException(); mStatefulRunnable = mock(StatefulRunnable.class, CALLS_REAL_METHODS); // setup state - no constructor has been run Field mStateField = StatefulRunnable.class.getDeclaredField("mState"); mStateField.setAccessible(true); mStateField.set(mStatefulRunnable, new AtomicInteger(StatefulRunnable.STATE_CREATED)); mStateField.setAccessible(false); } @Test public void testSuccess() throws Exception { runSuccess(); InOrder inOrder = inOrder(mStatefulRunnable); inOrder.verify(mStatefulRunnable).onSuccess(mResult); inOrder.verify(mStatefulRunnable).disposeResult(mResult); } @Test public void testClosesResultWhenOnSuccessThrows() throws Exception { doThrow(mException).when(mStatefulRunnable).onSuccess(mResult); try { runSuccess(); fail(); } catch (ConcurrentModificationException cme) { // expected } verify(mStatefulRunnable).disposeResult(mResult); } @Test public void testFailure() throws Exception { runFailure(); verify(mStatefulRunnable).onFailure(mException); } @Test public void testDoesNotRunAgainAfterStarted() throws Exception { mStatefulRunnable.mState.set(StatefulRunnable.STATE_STARTED); runSuccess(); verify(mStatefulRunnable, never()).getResult(); } @Test public void testCancellation() { mStatefulRunnable.cancel(); verify(mStatefulRunnable).onCancellation(); } @Test public void testDoesNotRunAfterCancellation() throws Exception { mStatefulRunnable.cancel(); runSuccess(); verify(mStatefulRunnable, never()).getResult(); } @Test public void testDoesNotCancelTwice() { mStatefulRunnable.cancel(); mStatefulRunnable.cancel(); verify(mStatefulRunnable).onCancellation(); } @Test public void testDoesNotCancelAfterStarted() { mStatefulRunnable.mState.set(StatefulRunnable.STATE_STARTED); mStatefulRunnable.cancel(); verify(mStatefulRunnable, never()).onCancellation(); } private void runSuccess() throws Exception { doReturn(mResult).when(mStatefulRunnable).getResult(); mStatefulRunnable.run(); } private void runFailure() throws Exception { doThrow(mException).when(mStatefulRunnable).getResult(); mStatefulRunnable.run(); } }